package com.onejson.ojmall.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.druid.util.StringUtils;
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
import com.onejson.ojmall.common.constant.StringConst;
import com.onejson.ojmall.common.domain.LoginLogVO;
import com.onejson.ojmall.common.domain.ResponseDTO;
import com.onejson.ojmall.common.domain.UserPermission;
import com.onejson.ojmall.common.enumeration.LoginLogResultEnum;
import com.onejson.ojmall.common.enumeration.UserTypeEnum;
import com.onejson.ojmall.common.util.OjBeanUtil;
import com.onejson.ojmall.entity.form.LoginForm;
import com.onejson.ojmall.entity.vo.LoginResultVO;
import com.onejson.ojmall.model.entity.UserEntity;
import com.onejson.ojmall.model.vo.SMenuVO;
import com.onejson.ojmall.model.vo.SRoleVO;
import com.onejson.ojmall.service.ILoginService;
import com.onejson.ojmall.service.SLoginLogService;
import com.onejson.ojmall.service.SRoleMenuService;
import com.onejson.ojmall.service.SRoleUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;

/**
 * 登录
 */
@Slf4j
@Service
public class LoginService implements ILoginService {

    @Resource
    private UserService userService;

    @Resource
    private SLoginLogService loginLogService;

    @Resource
    private SRoleUserService roleUserService;

    @Resource
    private SRoleMenuService roleMenuService;

    @Resource
    private ProtectPasswordService profectPasswordService;


    /**
     * 最大在线缓存人数
     */
    private static final long CACHE_MAX_ONLINE_PERSON_COUNT = 1000L;

    /**
     * 权限 缓存
     */
    private final ConcurrentMap<Long, UserPermission> permissionCache = new ConcurrentLinkedHashMap.Builder<Long, UserPermission>()
            .maximumWeightedCapacity(CACHE_MAX_ONLINE_PERSON_COUNT).build();


    /**
     * 用户登录
     *
     * @return 返回用户登录信息
     */
    public ResponseDTO<LoginResultVO> login(LoginForm loginForm, String ip) {

        // 验证登录名
        UserEntity userEntity = userService.getByLoginName(loginForm.getLoginName());
        if (null == userEntity) {
            return ResponseDTO.userErrorParam("登录名不存在！");
        }

        // 解密前端加密的密码
        String requestPassword = profectPasswordService.decryptPassword(loginForm.getPassword());

        // 密码错误
        if (!userEntity.getLoginPwd().equals(UserService.getEncryptPwd(requestPassword))) {
            return ResponseDTO.userErrorParam("登录名或密码错误！");
        }

        String saTokenLoginId = UserTypeEnum.ADMIN_EMPLOYEE.getValue() + StringConst.COLON + userEntity.getId();
        // 登录
        StpUtil.login(saTokenLoginId);


        // 获取登录结果信息
        LoginResultVO loginResultVO = getLoginResult(userEntity);

        // 设置 token
        loginResultVO.setToken(StpUtil.getTokenValue());

        return ResponseDTO.ok(loginResultVO);
    }

    /**
     * 获取登录结果信息
     */
    public LoginResultVO getLoginResult(UserEntity userEntity) {

        // 基础信息
        LoginResultVO loginResultVO = OjBeanUtil.copy(userEntity, LoginResultVO.class);

        // 前端菜单和功能点清单
        List<SRoleVO> roleList = roleUserService.getRoleIdList(Long.valueOf(userEntity.getId()));
        List<SMenuVO> menuAndPointsList = roleMenuService.getMenuList(roleList.stream().map(SRoleVO::getRoleId).collect(Collectors.toList()),
                userEntity.getAdministratorFlag());
        loginResultVO.setMenuList(menuAndPointsList);

        // 更新下后端权限缓存
        UserPermission userPermission = getUserPermission(Long.valueOf(userEntity.getId()));
        permissionCache.put(Long.valueOf(userEntity.getId()), userPermission);

        // 上次登录信息
        LoginLogVO loginLogVO = loginLogService.queryLastByUserId(Long.valueOf(userEntity.getId()), UserTypeEnum.ADMIN_EMPLOYEE, LoginLogResultEnum.LOGIN_SUCCESS);
        if (loginLogVO != null) {
            loginResultVO.setLastLoginIp(loginLogVO.getLoginIp());
            loginResultVO.setLastLoginIpRegion(loginLogVO.getLoginIpRegion());
            loginResultVO.setLastLoginTime(loginLogVO.getCreateTime());
            loginResultVO.setLastLoginUserAgent(loginLogVO.getUserAgent());
        }

        return loginResultVO;
    }


    /**
     * 获取用户的权限（包含 角色列表、权限列表）
     */
    private UserPermission getUserPermission(Long userId) {

        UserPermission userPermission = new UserPermission();
        userPermission.setPermissionList(new ArrayList<>());
        userPermission.setRoleList(new ArrayList<>());

        // 角色列表
        List<SRoleVO> roleList = roleUserService.getRoleIdList(userId);
        userPermission.getRoleList().addAll(roleList.stream().map(SRoleVO::getRoleCode).collect(Collectors.toSet()));

        // 前端菜单和功能点清单
        UserEntity userEntity = userService.getById(userId);

        List<SMenuVO> menuAndPointsList = roleMenuService.getMenuList(roleList.stream().map(SRoleVO::getRoleId).collect(Collectors.toList()),
                userEntity.getAdministratorFlag());

        // 权限列表
        HashSet<String> permissionSet = new HashSet<>();
        for (SMenuVO menu : menuAndPointsList) {
            if (menu.getPermsType() == null) {
                continue;
            }

            String perms = menu.getApiPerms();
            if (StringUtils.isEmpty(perms)) {
                continue;
            }
            //接口权限
            String[] split = perms.split(",");
            permissionSet.addAll(Arrays.asList(split));
        }
        userPermission.getPermissionList().addAll(permissionSet);

        return userPermission;
    }

}
